---
author: hongbo
date: "2020-04-13"
badge: release
title: Announcing BuckleScript 7.3
description: |
  Featuring major improvements like Generalized Uncurry Convention Support and
  unit value to undefined compilation.
---

## Overview

We are happy to announce that `bs-platform@7.3` is available for testing, you
can try it with `npm install bs-platform@7.3.1`.

For those unfamiliar with bs-platform, it is the platform for compiling
[ReasonML](https://reasonml.github.io/) and [OCaml](https://ocaml.org/) to fast
and readable JavaScript.

This is a major release with some highlighted features as below:

## Generalized uncurry calling convention support

You can use an uncurried function as conveniently as a curried one now, this is
an exciting change that we wrote a [separate
post](https://bucklescript.github.io/blog/2020/03/26/generalize-uncurry) for
details.

For uncurried support, we also fixed a long standing
[issue](https://github.com/BuckleScript/bucklescript/issues/4274) so that type
inference follows naturally using the new encoding.

```reason
bar
 -> Belt.Array.mapU((.b)=>b.foo /*no type annotation needed */)
```

## The `unit` value now compiles to `undefined`

In ReasonML, when a function does not return any meaningful value, it returns a
value that is `()` of type `unit`. In native backend, the dummy value `()` is
compiled into a const zero. We used to inherit this in JS backend as well.
However, this is a semantics mismatch since in JS, if the function does not
return anything, it defaults to `undefined`. In this release, we make it more
consistent with JS: compiling `()` into `undefined`. Since in JS, `return
undefined` can be ignored in tail position, this leads to some other nice
enhancement.

```reason
let log = x => Js.log(x)
```

The generated code used to be

```js
function log(x) {
  console.log(x);
  return /* () */ 0;
}
```

It's now

```js
function log(x) {
  console.log(x);
}
```

## Various improvements in code generation

We have increased the readability of the generated code in several common
places, we believe that we reached _an important milestone_ that if you write
code using features that have counterparts in JS, the generated code is
readable. This is not a small achievement given that quite a lot of the
compiler code base is shared between native backend and JS backend.

There are some features that are not available in JS, for example, complex
pattern matches, the readability of those pieces of generated code will
continue being improved.

Take several enhancement below as examples:

### Meaningful pattern match variable names

```reason
let popUndefined = s =>
  switch (s.root) {
  | None => Js.undefined
  | Some(x) =>
    s.root = x.tail;
    Js.Undefined.return(x.head);
  };
```

```diff
function popUndefined(s) {
-  var match = s.root;
-  if (match !== null) {
-    s.root = match.tail;
-    return match.head;
+  var x = s.root;
+  if (x !== undefined) {
+    s.root = x.tail;
+    return x.head;
   }

 }
```

When pattern match against a compounded expression, the compiler used to use a
temporary name `match`, now we employ better heuristics to generate meaningful
names for such temporary variables.

### Eliminate intermediate variable names when inlining

```diff
 function everyU(arr, b) {
   var len = arr.length;
-  var arr$1 = arr;
   var _i = 0;
-  var b$1 = b;
-  var len$1 = len;
   while(true) {
     var i = _i;
-    if (i === len$1) {
+    if (i === len) {
       return true;
-    } else if (b$1(arr$1[i])) {
-      _i = i + 1 | 0;
-      continue ;
-    } else {
+    }
+    if (!b(arr[i])) {
       return false;
     }
+    _i = i + 1 | 0;
+    continue ;
   };
 }
```

The above diff is the generated code for `Belt.Array.everyU`, the intermediate
variables were introduced when inlining an auxiliary function, such duplication
were removed in this release.

### Flatten if/else branch making use of JS's `early return` idiom

Take the same diff from above, you will notice that the second `else` following
`if(..) continue` is removed.

Below are similar diffs benefiting from such enhancement:

```diff
 function has(h, key) {
@@ -133,21 +123,18 @@ function has(h, key) {
   var nid = Caml_hash_primitive.caml_hash_final_mix(Caml_hash_primitive.caml_hash_mix_string(0, key)) & (h_buckets.length - 1 | 0);
   var bucket = h_buckets[nid];
   if (bucket !== undefined) {
-    var key$1 = key;
     var _cell = bucket;
     while(true) {
       var cell = _cell;
-      if (cell.key === key$1) {
+      if (cell.key === key) {
         return true;
-      } else {
-        var match = cell.next;
-        if (match !== undefined) {
-          _cell = match;
-          continue ;
-        } else {
-          return false;
-        }
       }
+      var nextCell = cell.next;
+      if (nextCell === undefined) {
+        return false;
+      }
+      _cell = nextCell;
+      continue ;
     };
   } else {
     return false;
@@ -155,17 +142,17 @@ function has(h, key) {
 }
```

```diff
--- a/lib/js/belt_List.js
+++ b/lib/js/belt_List.js
@@ -15,9 +15,8 @@ function head(x) {
 function headExn(x) {
   if (x) {
     return x[0];
-  } else {
-    throw new Error("headExn");
   }
+  throw new Error("headExn");
 }
```

### For loop minor-enhancement

```diff
 function shuffleInPlace(xs) {
   var len = xs.length;
-  for(var i = 0 ,i_finish = len - 1 | 0; i <= i_finish; ++i){
+  for(var i = 0; i < len; ++i){
     swapUnsafe(xs, i, Js_math.random_int(i, len));
   }
-  return /* () */0;
+
 }
```

Reason's `for .. in` only provide closed interval iterating, so it is quite
common to write `for (i in 0 to Array.length(x) - 1) { .. }`, we did the
tweaking above to make the generated code more readable.

A full list of changes is available in our [Changelog
file](https://github.com/BuckleScript/bucklescript/blob/master/Changes.md#73).
